package com.kedacom.ctsp.authz.oauth2.client.service;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.kedacom.ctsp.authz.AuthenticationService;
import com.kedacom.ctsp.authz.entity.AuthResource;
import com.kedacom.ctsp.authz.entity.Authentication;
import com.kedacom.ctsp.authz.entity.AuthzTypeEnum;
import com.kedacom.ctsp.authz.exception.UsernameNotFoundException;
import com.kedacom.ctsp.authz.oauth2.core.OAuth2Authentication;
import com.kedacom.ctsp.authz.oauth2.core.vo.AuthResourceQueryParam;
import com.kedacom.ctsp.web.controller.message.ResponseMessage;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class Oauth2AuthenticationService implements AuthenticationService {


    @Autowired
    private OAuth2ResourceService oAuth2ResourceService;

    //<userName,<resource,List<AuthResource>>>
    private Cache<String, Map<String, List<AuthResource>>> authenticationCache = CacheBuilder.newBuilder()
            .expireAfterWrite(30, TimeUnit.SECONDS)
            .build();

    @Override
    public Authentication loadUserByUsername(String username) throws UsernameNotFoundException {
        return null;
    }

    @Override
    public Set<AuthResource> getAuthResource(Authentication authentication) {
        ResponseMessage<Set<AuthResource>> response = oAuth2ResourceService.getAuthResource((OAuth2Authentication) authentication);
        if (response.is2xxSuccessful()) {
            return response.getResult();
        }
        return null;
    }

    @Override
    public List<AuthResource> loadResources(Authentication user, Set<String> resources, AuthzTypeEnum authzTypeEnum) {

        //资源
        List<AuthResource> userResources = new ArrayList<>();

        //判断缓存权限资源，加载未加载到缓存的资源
        getUserAuthResourceFromCache(user, resources, userResources);

        //通过接口从Server获取
        return userResources;
    }

    /**
     * 从server端加载资源
     *
     * @param user
     * @param needLoadResources
     * @return
     */
    private List<AuthResource> getAuthResourceFromServer(Authentication user, Set<String> needLoadResources) {

        ResponseMessage<List<AuthResource>> plainResources = oAuth2ResourceService.loadResources(new AuthResourceQueryParam(user, needLoadResources));
        if (plainResources.getStatus() != 200) {
            //接口请求异常
            return null;
        }

        List<AuthResource> authResources = new ArrayList<>();

        for (AuthResource authResource : plainResources.getResult()) {
            authResources.add(authResource);

            //记录缓存
            addCache(user.getUser().getUsername(), authResource.getSign(), authResource);

            if (needLoadResources != null) {
                //加载成功的资源，移除，剩下的是加载成功，但没有权限的
                needLoadResources.remove(authResource.getSign());
            }

        }

        if (needLoadResources != null) {
            //添加空列表到缓存，表示已经调用接口加载过但是没有缓存
            for (String source : needLoadResources) {
                // 记录缓存
                addCache(user.getUser().getUsername(), source, null);
            }
        }

        return authResources;
    }

    /**
     * 添加缓存
     *
     * @param userName
     * @param source
     * @param authResource
     */
    private void addCache(String userName, String source, AuthResource authResource) {

        Map<String, List<AuthResource>> userAllAuthResources = authenticationCache.getIfPresent(userName);
        if (userAllAuthResources == null) {
            userAllAuthResources = new HashMap<>();
            authenticationCache.put(userName, userAllAuthResources);
        }

        List<AuthResource> sourceAuthResources = userAllAuthResources.get(source);
        if (sourceAuthResources == null) {
            sourceAuthResources = new ArrayList<>();
            userAllAuthResources.put(source, sourceAuthResources);
        }

        if (authResource == null) {
            return;
        }
        sourceAuthResources.add(authResource);
    }


    /**
     * 从缓存获取资源
     *
     * @param user
     * @param resources
     * @param userResources
     * @return 记录需要加载的资源
     */
    private Set<String> getUserAuthResourceFromCache(Authentication user, Set<String> resources, List<AuthResource> userResources) {

        Set<String> needLoadResources = new HashSet<>();

        //用户所有权限
        Map<String, List<AuthResource>> userAllAuthResources = authenticationCache.getIfPresent(user.getUser().getUsername());
        if (userAllAuthResources == null) {

            //缓存中没有，该用户信息

            //调用接口加载
            if (getAuthResourceFromServer(user, needLoadResources) == null) {
                //加载失败
                return null;
            }

            //重新获取
            userAllAuthResources = authenticationCache.getIfPresent(user.getUser().getUsername());
            if (userAllAuthResources == null) {
                return null;
            }
        }

        if (CollectionUtils.isEmpty(resources)) {
            //全部资源
            resources.addAll(userAllAuthResources.keySet());
        }


        //获取资源
        for (String resource : resources) {
            List<AuthResource> sourceAuthResources = userAllAuthResources.get(resource);

            if (sourceAuthResources == null) {
                //记录需要加载的资源
                needLoadResources.addAll(resources);
                continue;
            }
            if (sourceAuthResources.size() <= 0) {
                //已经加载过，没有这个权限
                continue;
            }

            userResources.addAll(sourceAuthResources);
        }
        return needLoadResources;
    }


    @Override
    public void logout(String username) {
        authenticationCache.invalidate(username);
    }
}
